package cn.code4java.springbok.utils;

/**
 * @ClassName CodeUtils
 * @Description: 券码生成工具
 * @Author zhonghengtech
 * @Date 2024/6/5
 * @Version V1.0
 **/
public class CodeUtils {

    private static long workerId = 1;
    private static long sequence = 0L;
    private static long twepoch = 1609459200000L; // 起始时间戳，如：2021-01-01 00:00:00
    private static long workerIdBits = 10L; // 机器ID所占位数
    private static long sequenceBits = 12L; // 序列号所占位数
    private static long workerIdShift = sequenceBits;
    private static long timestampLeftShift = sequenceBits + workerIdBits;
    private static long sequenceMask = -1L ^ (-1L << sequenceBits);
    private static long lastTimestamp = -1L;

    /**
     * 生成带前缀券码
     * @param prx
     * @return
     */
    public synchronized static String generateCouponCode(String prx) {
        return prx + generateCouponCode();
    }

    /**
     * 生成券码
     * @return
     */
    public synchronized static String generateCouponCode() {
        long timestamp = System.currentTimeMillis();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException("时钟回拨，无法生成券码");
        }

        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        long id = ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;

        return String.valueOf(id);
    }

    private static long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}
